CQCIS.workflow.Palette = Ext.extend(Ext.Panel, {
    parallelizable: false,
    nodes: null,
    lines: null,
    selectedObj: null,
    selectedLineFrom: null,
    selectedLineTo: null,
    mouseX: -1,
    mouseY: -1,
    mouseEndX: -1,
    mouseEndY: -1,
    action: null,
    lineFlag: null,
    multiSelect: false,
    ctrlKey: false,
    nodeMirror: null,
    lineMirror: null,
    bottomHeight: 100,
    rightWidth: 100,
    readOnly: false,
    statusbar: false,
    getX: function(x) {
        return (x + this.body.dom.scrollLeft);
    },
    getY: function(y) {
        return (y + this.body.dom.scrollTop);
    },
    getMouseX: function() {
        return window.event.x;
    },
    getMouseY: function() {
        return window.event.y;
    },
    insertObjInArr: function(arr, s) {
        if (arr === null) {
            arr = [];
        }
        arr.push(s);
        return arr;
    },
    removeObjInArr: function(arr, s) {
        var tArr = null;
        var count = 0;
        if (arr !== null) {
            tArr = [];
            var num = arr.length;
            for (var i = 0; i < num; i++) {
                if (arr[i] != s) {
                    tArr[count] = arr[i];
                    count++;
                }
            }
        }
        return tArr;
    },
    isInArr: function(arr, s) {
        var res = false;
        if (arr !== null) {
            var num = arr.length;
            for (var i = 0; i < num; i++) {
                if (arr[i] == s) {
                    res = true;
                    break;
                }
            }
        }
        return res;
    },
    onRender: function(ct, position) {
        CQCIS.workflow.Palette.superclass.onRender.call(this, ct, position);
        
        this.nodes = [];
        this.lines = [];
        this.selectedObj = [];
        this.selectedLineFrom = [];
        this.selectedLineTo = [];
        
        this.paletteEl = this.body.createChild({
            tag: 'div',
            cls: 'x-workflow-palette'
        });
        this.el.unselectable();
        this.paletteEl.on('contextmenu', function(evt) {
            evt.stopEvent();
            return false;
        });
        
        if (this.statusbar === true && this.getBottomToolbar().getXType() == 'statusbar') {
            this.statusbar = this.getBottomToolbar();
            
            this.mpbar = this.statusbar.addText('当前坐标：0, 0');
            Ext.fly(this.mpbar.getEl().parentNode).addClass('x-status-text-panel').createChild({
                cls: 'spacer'
            });
            this.statusbar.addText(' ');
            
            this.selbar = this.statusbar.addText('当前选中对象：无');
            Ext.fly(this.selbar.getEl().parentNode).addClass('x-status-text-panel').createChild({
                cls: 'spacer'
            });
            this.statusbar.addText(' ');
        }
        
        if (!this.readOnly) {
            this.body.on('mousedown', function() {
                this.point('down');
                this.eventStart();
            }, this);
            
            this.body.on('mousemove', function() {
                if (this.action !== null) {
                    switch (this.action) {
                        case "nodedown":
                            this.moveSelectedObj();
                            break;
                        case "drawline":
                            this.drawMirrorLineTo(null);
                            break;
                        case "moveline":
                            this.moveLine(null);
                            break;
                        case "blankdown":
                            this.drawMirrorNode();
                            break;
                        default:
                    }
                }
                
                if (this.mpbar) {
                    Ext.fly(this.mpbar.getEl()).update('当前坐标：' + this.getMouseX() + ', ' + this.getMouseY());
                }
            }, this);
            
            this.body.on('mouseup', function() {
                if (this.action !== null) {
                    this.point('up');
                    var selNode = this.getEventNode('up');
                    switch (this.action) {
                        case "nodedown":
                            this.moveSelectedObjEnd();
                            break;
                        case "drawline":
                            this.drawLineEnd(selNode);
                            break;
                        case "moveline":
                            this.moveLineEnd(selNode);
                            break;
                        case "blankdown":
                            this.drawMirrorNodeEnd();
                            break;
                        default:
                    }
                }
                this.resizePalette();
                this.action = null;
                
                this.updateSelectedInfo();
            }, this);
            
            this.el.on('keydown', function(evt) {
                if (window.event.ctrlKey) {
                    this.ctrlKey = true;
                }
                switch (window.event.keyCode) {
                    case 46:
                        this.removeSelected();
                        break;
                    case 65:
                        if (window.event.ctrlKey) {
                            this.selectAll();
                            this.multiSelect = true;
                            window.event.returnValue = false;
                        }
                        break;
                    case 37:
                    case 38:
                    case 39:
                    case 40:
                        this.moveSelectedObjByKey(window.event.keyCode);
                        break;
                }
            }, this);
            
            this.el.on('keyup', function() {
                this.ctrlKey = false;
            }, this);
            
            this.lineMirror = this.addLine({
                textFlag: false,
                mirrorFlag: true
            });
            this.lineMirror.setDisplay('none');
            this.lineMirror.obj.strokecolor = '#28437a';
            
            this.nodeMirror = this.addNode({
                strokeFlag: true,
                shadowFlag: false,
                textFlag: false,
                mirrorFlag: true
            });
            this.nodeMirror.setDisplay('none');
            this.nodeMirror.obj.strokecolor = 'ccc';
            this.nodeMirror.obj.fillcolor = '#fff';
            this.nodeMirror.obj.style.zIndex = '2000';
            this.nodeMirror.strokeObj.dashstyle = 'Dash';
        }
        
        this.on('beforedestroy', this._destroy);
    },
    point: function(flag) {
        if (flag == 'down') {
            this.mouseX = this.getMouseX();
            this.mouseY = this.getMouseY();
        } else if (flag == 'up') {
            this.mouseEndX = this.getMouseX();
            this.mouseEndY = this.getMouseY();
        }
    },
    getEventNode: function(flag) {
        var res = null;
        var nodeNum = this.nodes.length;
        var node = null;
        var x;
        var y;
        if (flag == 'down') {
            x = this.mouseX;
            y = this.mouseY;
        } else if (flag == 'up') {
            x = this.mouseEndX;
            y = this.mouseEndY;
        }
        for (var i = (nodeNum - 1); i >= 0; i--) {
            node = this.nodes[i];
            if (node.pointInObj(x, y)) {
                res = node;
                break;
            }
        }
        return res;
    },
    getEventLine: function() {
        var res = null;
        var lineNum = this.lines.length;
        var line = null;
        var x = this.mouseX;
        var y = this.mouseY;
        var isStroke = -1;
        for (var i = (lineNum - 1); i >= 0; i--) {
            line = this.lines[i];
            if (line.pointInObj(x, y)) {
                if (res === null || line.obj.style.zIndex == '22') {
                    res = null;
                    res = this.insertObjInArr(res, line);
                    isStroke = line.pointInStroke(x, y);
                    if (isStroke === 0) {
                        this.selectedLineTo = [];
                        this.selectedLineFrom = [];
                        this.selectedLineTo = this.insertObjInArr(this.selectedLineTo, line);
                    } else if (isStroke == 1) {
                        this.selectedLineTo = [];
                        this.selectedLineFrom = [];
                        this.selectedLineFrom = this.insertObjInArr(this.selectedLineFrom, line);
                    }
                }
            }
        }
        return res;
    },
    moveSelectedObj: function() {
        var x = this.getMouseX();
        var y = this.getMouseY();
        var num = this.selectedObj.length;
        var lineNum = this.lines.length;
        var line = null;
        for (var i = 0; i < num; i++) {
            if (this.selectedObj[i].move) {
                this.selectedObj[i].move(x, y, this.mouseX, this.mouseY);
                for (var j = 0; j < lineNum; j++) {
                    line = this.lines[j];
                    if ((line.fromNode == this.selectedObj[i]) || (line.toNode == this.selectedObj[i])) {
                        line.relink();
                    }
                }
            }
        }
    },
    moveSelectedObjByKey: function(keyCode) {
        var offLeft = 0;
        var offTop = 0;
        switch (keyCode) {
            case 37:
                offLeft = -1;
                break;
            case 38:
                offTop = -1;
                break;
            case 39:
                offLeft = 1;
                break;
            case 40:
                offTop = 1;
                break;
        }
        
        var num = this.selectedObj.length;
        var lineNum = this.lines.length;
        var line = null;
        for (var i = 0; i < num; i++) {
            if (this.selectedObj[i].moveTo) {
                this.selectedObj[i].moveTo(this.selectedObj[i].left + offLeft, this.selectedObj[i].top + offTop);
                for (var j = 0; j < lineNum; j++) {
                    line = this.lines[j];
                    if ((line.fromNode == this.selectedObj[i]) || (line.toNode == this.selectedObj[i])) {
                        line.relink();
                    }
                }
            }
        }
    },
    moveSelectedObjEnd: function() {
        var num = this.selectedObj.length;
        for (var i = 0; i < num; i++) {
            if (this.selectedObj[i].moveEnd) {
                this.selectedObj[i].moveEnd();
            }
        }
    },
    moveLine: function() {
        var x = this.getMouseX();
        var y = this.getMouseY();
        var num = this.selectedLineTo.length;
        for (var i = 0; i < num; i++) {
            this.selectedLineTo[i].setTo(x, y, null);
        }
        num = this.selectedLineFrom.length;
        for (var j = 0; j < num; j++) {
            this.selectedLineFrom[j].setFrom(x, y, null);
        }
    },
    moveLineEnd: function(selNode) {
        var num = this.selectedLineTo.length;
        if (selNode !== null) {
            for (var i = 0; i < num; i++) {
                if (this.checkLine(this.selectedLineTo[i].fromNode, selNode)) {
                    this.selectedLineTo[i].setTo(this.mouseEndX, this.mouseEndY, selNode);
                    this.selectedLineTo[i].relink();
                } else {
                    this.selectedLineTo[i].relink();
                }
            }
        } else {
            for (var j = 0; j < num; j++) {
                this.selectedLineTo[j].relink();
            }
        }
        this.selectedLineTo = [];
        num = this.selectedLineFrom.length;
        if (selNode !== null) {
            for (var k = 0; k < num; k++) {
                if (this.checkLine(selNode, this.selectedLineFrom[k].toNode)) {
                    this.selectedLineFrom[k].setFrom(this.mouseEndX, this.mouseEndY, selNode);
                    this.selectedLineFrom[k].relink();
                } else {
                    this.selectedLineFrom[k].relink();
                }
            }
        } else {
            for (var l = 0; l < num; l++) {
                this.selectedLineFrom[l].relink();
            }
        }
        this.selectedLineFrom = [];
    },
    drawLineEnd: function(selNode) {
        if (selNode !== null) {
            this.drawMirrorLineTo(selNode);
            if (this.checkLine(this.lineMirror.fromNode, this.lineMirror.toNode)) {
                var line = this.addLine();
                line.link(this.lineMirror);
                this.clearSelected();
            }
        }
        this.lineMirror.setDisplay('none');
    },
    drawMirrorLineFrom: function(selObj) {
        this.lineMirror.setFrom(this.mouseX, this.mouseY, selObj);
        this.lineMirror.setTo(this.mouseX, this.mouseY, selObj);
        this.lineMirror.setDisplay('');
    },
    drawMirrorLineTo: function(selObj) {
        var x = this.getMouseX();
        var y = this.getMouseY();
        this.lineMirror.setTo(x, y, selObj);
    },
    drawMirrorNodeStart: function() {
        this.multiSelect = false;
        this.nodeMirror.setLeft(this.getX(this.mouseX));
        this.nodeMirror.setTop(this.getY(this.mouseY));
        this.nodeMirror.setHeight(0);
        this.nodeMirror.setWidth(0);
    },
    drawMirrorNode: function() {
        var x = this.getMouseX();
        var y = this.getMouseY();
        this.nodeMirror.setWidth(Math.abs(this.getX(x) - this.getX(this.mouseX)));
        this.nodeMirror.setHeight(Math.abs(this.getY(y) - this.getY(this.mouseY)));
        if (this.getX(x) < this.getX(this.mouseX)) {
            this.nodeMirror.setLeft(this.getX(x));
        }
        if (this.getY(y) < this.getY(this.mouseY)) {
            this.nodeMirror.setTop(this.getY(y));
        }
        this.nodeMirror.setDisplay('');
    },
    drawMirrorNodeEnd: function() {
        this.nodeMirror.setDisplay('none');
        if (this.embodyObj()) {
            this.multiSelect = true;
        }
    },
    embodyObj: function() {
        var res = false;
        var x1 = this.nodeMirror.left;
        var x2 = this.nodeMirror.left + this.nodeMirror.width;
        var y1 = this.nodeMirror.top;
        var y2 = this.nodeMirror.top + this.nodeMirror.height;
        var nodeNum = this.nodes.length;
        var lineNum = this.lines.length;
        var node = null;
        var line = null;
        for (var i = 0; i < nodeNum; i++) {
            node = this.nodes[i];
            if ((x1 <= node.left) && (x2 >= (node.left + node.width)) && (y1 <= node.top) && (y2 >= (node.top + node.height))) {
                node.setSelected();
                this.selectedObj = this.insertObjInArr(this.selectedObj, node);
                node.x = 0;
                node.y = 0;
                node.mouseX = node.left;
                node.mouseY = node.top;
                res = true;
            }
        }
        for (var j = 0; j < lineNum; j++) {
            line = this.lines[j];
            if ((x1 <= Math.min(line.fromX, line.toX)) && (x2 >= Math.max(line.fromX, line.toX)) && (y1 <= Math.min(line.fromY, line.toY)) && (y2 >= Math.max(line.fromY, line.toY))) {
                line.setSelected();
                this.selectedObj = this.insertObjInArr(this.selectedObj, line);
                res = true;
            }
        }
        return res;
    },
    checkLine: function(fromNode, toNode) {
        if (toNode.type == 'start') {
            Ext.Msg.alert('提示', "连线的终点不能是开始节点！");
            return false;
        }
        
        if (fromNode.type == 'end') {
            Ext.Msg.alert('提示', "连线的起点不能是结束节点！");
            return false;
        }
        var res = true;
        if (fromNode == toNode) {
            res = false;
        }
        var len = this.lines.length;
        var line = null;
        for (var i = 0; i < len; i++) {
            line = this.lines[i];
            if ((line.fromNode == fromNode && line.toNode == toNode) || (line.fromNode == toNode && line.toNode == fromNode)) {
                res = false;
                Ext.Msg.alert('提示', "两点之间已经存在连线！");
                break;
            }
            
            if (this.parallelizable === false && (line.fromNode == fromNode || line.toNode == toNode)) {
                res = false;
                Ext.Msg.alert('提示', "不允许绘制并行节点！");
                break;
            }
        }
        return res;
    },
    clearSelected: function() {
        var num = this.selectedObj.length;
        for (var i = 0; i < num; i++) {
            this.selectedObj[i].clearSelected();
        }
        this.selectedObj = [];
    },
    selectAll: function() {
        this.selectedObj = [];
        var num = this.nodes.length;
        var obj = null;
        for (var i = 0; i < num; i++) {
            obj = this.nodes[i];
            obj.setSelected();
            this.selectedObj = this.insertObjInArr(this.selectedObj, obj);
            obj.x = 0;
            obj.y = 0;
            obj.mouseX = obj.left;
            obj.mouseY = obj.top;
        }
        num = this.lines.length;
        obj = null;
        for (var j = 0; j < num; j++) {
            obj = this.lines[j];
            obj.setSelected();
            this.selectedObj = this.insertObjInArr(this.selectedObj, obj);
        }
        this.updateSelectedInfo();
    },
    removeSelected: function() {
        var num = this.nodes.length;
        var obj = null;
        var arr = [];
        var count = 0;
        for (var i = 0; i < num; i++) {
            obj = this.nodes[i];
            if (obj.selected) {
                if (obj.type != 'start' && obj.type != 'end') {
                    obj.remove();
                } else {
                    Ext.Msg.alert('提示', '不能删除开始或者结束节点！');
                    obj.clearSelected();
                    arr.push(obj);
                    count++;
                }
            } else {
                arr.push(obj);
                count++;
            }
        }
        this.nodes = arr;
        num = this.lines.length;
        obj = null;
        arr = [];
        count = 0;
        for (var j = 0; j < num; j++) {
            obj = this.lines[j];
            if (obj.selected) {
                obj.remove();
            } else {
                arr[count] = obj;
                count++;
            }
        }
        this.lines = arr;
        this.selectedObj = [];
        this.updateSelectedInfo();
    },
    resizePalette: function() {
        var obj = this.paletteEl.dom;
        var maxWidth = -1;
        var maxHeight = -1;
        var num = this.nodes.length;
        var node = null;
        for (var i = 0; i < num; i++) {
            node = this.nodes[i];
            if (maxWidth < (node.left + node.width)) {
                maxWidth = node.left + node.width;
            }
            if (maxHeight < (node.top + node.height)) {
                maxHeight = node.top + node.height;
            }
        }
        if (maxHeight > this.body.getHeight()) {
            obj.style.height = (maxHeight + this.bottomHeight) + 'px';
        } else {
            obj.style.height = '100%';
        }
        if (maxWidth > this.body.getWidth()) {
            obj.style.width = (maxWidth + this.rightWidth) + 'px';
        } else {
            obj.style.width = '100%';
        }
    },
    eventStart: function() {
        if (this.ctrlKey) {
            this.multiSelect = true;
        }
        var selNode = this.getEventNode('down');
        var selLine = this.getEventLine();
        if (!this.multiSelect) {
            this.clearSelected();
        }
        if (selNode !== null) {
            if (!this.isInArr(this.selectedObj, selNode)) {
                if (!this.ctrlKey) {
                    this.multiSelect = false;
                    this.clearSelected();
                }
                selNode.setSelected();
                this.selectedObj = this.insertObjInArr(this.selectedObj, selNode);
            } else {
                if (this.ctrlKey) {
                    selNode.clearSelected();
                    this.selectedObj = this.removeObjInArr(this.selectedObj, selNode);
                }
            }
            if (this.lineFlag === null) {
                this.action = 'nodedown';
            } else if (this.lineFlag !== null) {
                this.action = 'drawline';
                this.drawMirrorLineFrom(selNode);
            }
        } else if (selLine !== null) {
            for (var i = 0; i < selLine.length; i++) {
                if (!this.isInArr(this.selectedObj, selLine[i])) {
                    if (!this.ctrlKey) {
                        this.multiSelect = false;
                    }
                    selLine[i].setSelected();
                    this.selectedObj = this.insertObjInArr(this.selectedObj, selLine[i]);
                } else {
                    if (this.ctrlKey) {
                        selLine[i].clearSelected();
                        this.selectedObj = this.removeObjInArr(this.selectedObj, selLine[i]);
                    }
                }
            }
            if (this.selectedLineTo.length > 0) {
                this.action = 'moveline';
                for (var j = 0; j < this.selectedLineTo.length; j++) {
                    this.selectedLineTo[j].setMoveSelected();
                }
            }
            if (this.selectedLineFrom.length > 0) {
                this.action = 'moveline';
                for (var k = 0; k < this.selectedLineFrom.length; k++) {
                    this.selectedLineFrom[k].setMoveSelected();
                }
            }
        } else {
            this.action = 'blankdown';
            if (!this.ctrlKey) {
                this.clearSelected();
                this.drawMirrorNodeStart();
            }
        }
    },
    addNode: function(config) {
        config = config ? config : {};
        
        var node;
        if (Ext.isArray(config)) {
            Ext.each(config, function(c) {
                Ext.apply(c, {
                    ownerCt: this
                });
                node = new CQCIS.workflow.Node(c);
            }, this);
        } else {
            Ext.apply(config, {
                ownerCt: this
            });
            node = new CQCIS.workflow.Node(config);
        }
        
        this.resizePalette();
        return node;
    },
    addLine: function(config) {
        config = config ? config : {};
        
        var line;
        if (Ext.isArray(config)) {
            Ext.each(config, function(c) {
                Ext.apply(c, {
                    ownerCt: this
                });
                line = new CQCIS.workflow.Line(c);
            }, this);
        } else {
            Ext.apply(config, {
                ownerCt: this
            });
            line = new CQCIS.workflow.Line(config);
        }
        
        return line;
    },
    findNode: function(nodeId) {
        if (nodeId === undefined) {
            return null;
        }
        
        for (var i = 0; i < this.nodes.length; i++) {
            if (this.nodes[i].id == nodeId) {
                return this.nodes[i];
            }
        }
    },
    updateSelectedInfo: function() {
        if (this.selbar) {
            var selText = [], extraText = '';
            for (var i = 0; i < this.selectedObj.length && i < 3; i++) {
                selText.push(this.selectedObj[i].toString());
            }
            if (this.selectedObj.length > 3) {
                extraText = '……';
            }
            Ext.fly(this.selbar.getEl()).update('当前选中对象：' + (selText.length > 0 ? selText.join('、') + extraText : '无'));
        }
    },
    clearPalette: function() {
        var i = 0;
        for (i = this.nodes.length - 1; i > -1; i--) {
            this.nodes[i].remove();
        }
        this.nodes = [];
        for (i = this.lines.length - 1; i > -1; i--) {
            this.lines[i].remove();
        }
        this.lines = [];
    },
    isValid: function() {
        var flag = true;
        for (var i = 0; i < this.nodes.length; i++) {
            var node = this.nodes[i];
            if (node.type != 'start' && node.fromId.length === 0) {
                flag = false;
                break;
            }
            if (node.type != 'end' && node.toId.length === 0) {
                flag = false;
                break;
            }
            if (!this.parallelizable) {
                if (node.fromId.length > 1 || node.toId.length > 1) {
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    },
    setLineFlag: function(flag) {
        this.lineFlag = flag;
    },
    getNodes: function() {
        return this.nodes;
    },
    getLines: function() {
        return this.lines;
    },
    _destroy: function() {
        this.clearPalette();
        this.body.removeAllListeners();
        this.el.removeAllListeners();
        this.paletteEl.remove();
        return true;
    }
});
